package com.niiwoo.civet.trade.service.local.newRefund.refundDeal.core;

import com.alibaba.fastjson.JSON;
import com.niiwoo.civet.account.dto.response.AccountCompanyDTO;
import com.niiwoo.civet.base.enums.FeeTypeEnum;
import com.niiwoo.civet.trade.constant.AccountConfigConstants;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.newRefund.RefundFeeDTO;
import com.niiwoo.civet.trade.dto.newRefund.RefundOrderDetailDTO;
import com.niiwoo.civet.trade.enums.RefundTradeTypeEnum;
import com.niiwoo.civet.trade.service.local.newRefund.common.RefundCommonService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.BusinessTypeEnum;
import com.niiwoo.tripod.lanmao.enums.TransactionTypeEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 金额分配
 */
@Service
@Slf4j
public class RefundAllotFeeForGuaranteeService {

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private LanMaoSequence lanMaoSequence;

    @Autowired
    private RefundOrderDetailMapperExt refundOrderDetailMapperExt;

    @Autowired
    private RefundOrderDetailBizMapperExt refundOrderDetailBizMapperExt;

    @Autowired
    private ProjectInvestorPlanMapperExt projectInvestorPlanMapperExt;
    @Autowired
    private FeeCalcForRefundService feeCalcForRefundService;
    @Autowired
    private ProjectGuaranteePlanMapperExt projectGuaranteePlanMapperExt;
    @Autowired
    private AccountConfigMapper accountConfigMapper;
    @Autowired
    private ProjectBorrowerSummaryMapperExt projectBorrowerSummaryMapperExt;
    @Autowired
    private ProjectMapperExt projectMapperExt;
    @Autowired
    private RefundCommonService refundCommonService;
    @Autowired
    private ProjectGuaranteeServicePlanMapperExt projectGuaranteeServicePlanMapperExt;


    /**
     * 垫付分账
     * @param refundOrder
     * @return
     */
    @Transactional(propagation = Propagation.MANDATORY)
    public List<RefundOrderDetailDTO> allotFee(RefundOrder refundOrder){
        Long projectId = refundOrder.getProjectId();
        String batchNo = refundOrder.getBatchNo();
        String freezeRequestNo = refundOrder.getFreezeRequestNo();
        ProjectBorrowerSummary summary = projectBorrowerSummaryMapperExt.selectByPrimaryKey(projectId);
        Project project = projectMapperExt.selectByPrimaryKey(projectId);
        //查询投资人回款计划
        List<ProjectInvestorPlan> investorPlans = projectInvestorPlanMapperExt.listProjectPeriodInvestorPlanReceiveDate(projectId, refundOrder.getCompareDate());
        final List<RefundOrderDetailDTO> refundOrderDetailDTOs = new ArrayList<>();
        for (ProjectInvestorPlan investorPlan : investorPlans) {
            // 目前只垫付本金+利息、
            BigDecimal capital = investorPlan.getCapital().subtract(investorPlan.getReceivedCapital());
            BigDecimal interest = investorPlan.getInterest().subtract(investorPlan.getReceivedInterest());
            if(capital.add(interest).compareTo(BigDecimal.ZERO) <= 0){
                continue;
            }
            RefundOrderDetailDTO refundOrderDetailDTO = new RefundOrderDetailDTO();
            refundOrderDetailDTO.setId(snowflakeIdWorker.nextId());
            refundOrderDetailDTO.setRefundOrderId(refundOrder.getId());
            refundOrderDetailDTO.setBatchNo(batchNo);
            refundOrderDetailDTO.setProjectId(projectId);
            refundOrderDetailDTO.setBorrowUserId(refundOrder.getBorrowUserId());
            refundOrderDetailDTO.setDetailRequestNo(lanMaoSequence.getRequestNo());
            refundOrderDetailDTO.setTradeType(TransactionTypeEnum.COMPENSATORY.name());
            refundOrderDetailDTO.setCreateTime(new Date());
            refundOrderDetailDTO.setUpdateTime(new Date());
            refundOrderDetailMapperExt.insertSelective(refundOrderDetailDTO);

            RefundOrderDetailBiz biz = new RefundOrderDetailBiz();
            biz.setId(snowflakeIdWorker.nextId());
            biz.setRefundOrderId(refundOrder.getId());
            biz.setBatchNo(batchNo);
            biz.setProjectId(projectId);
            biz.setBorrowUserId(refundOrder.getBorrowUserId());
            biz.setCurrentPeriod(investorPlan.getCurrentPeriod());
            biz.setDetailRequestNo(refundOrderDetailDTO.getDetailRequestNo());
            biz.setBizType(BusinessTypeEnum.COMPENSATORY.name());
            biz.setBackPlanId(investorPlan.getId());
            biz.setFreezeRequestNo(freezeRequestNo);
            biz.setSourceUserId(refundOrder.getSourceUserId());
            biz.setSourceAccountId(refundOrder.getSourceAccountId());
            biz.setSourcePlatformUserNo(refundOrder.getSourcePlatformUserNo());
            biz.setTargetAccountId(investorPlan.getAccountId());
            biz.setTargetUserId(investorPlan.getUserId());
            biz.setTargetPlatformUserNo(investorPlan.getPlatformUserNo());

            biz.setCapital(investorPlan.getCapital().subtract(investorPlan.getReceivedCapital()));
            biz.setInterest(investorPlan.getInterest().subtract(investorPlan.getReceivedInterest()));
            biz.setAmount(biz.getCapital().add(biz.getInterest()));
            biz.setCreateTime(new Date());
            biz.setUpdateTime(new Date());
            biz.setTradeType(refundOrder.getTradeType());
            refundOrderDetailBizMapperExt.insertSelective(biz);

            refundOrderDetailDTOs.add(refundOrderDetailDTO);
            final List<RefundOrderDetailBiz> refundOrderDetailBizs = new ArrayList<>();
            refundOrderDetailBizs.add(biz);
            refundOrderDetailDTO.setRefundOrderDetailBizList(refundOrderDetailBizs);
        }

        //平台管理费，咨询服务垫付分账
        if(refundOrder.getManageFee().add(refundOrder.getConsultingFee()).compareTo(BigDecimal.ZERO) > 0){
            List<Integer> periods = this.spiltPeriods(refundOrder.getPeriods());
            List<ProjectBorrowerPlanNew> needRefundProjectBorrowPlanNew = feeCalcForRefundService.getNeedRefundProjectBorrowPlanNew(refundOrder.getOptType(), refundOrder.getCompareDate() , summary , periods);
            List<ProjectGuaranteeServicePlan> servicePlans = projectGuaranteeServicePlanMapperExt.listServiceFeesReceiveByProjectId(projectId);
            List<ProjectBorrowerPlanNew> guaranteePlans = new ArrayList<>(needRefundProjectBorrowPlanNew);
            log.info("处理期数前标的{},{},原对象{}",refundOrder.getProjectId(), JSON.toJSONString(guaranteePlans),JSON.toJSONString(needRefundProjectBorrowPlanNew));

            for (ProjectBorrowerPlanNew planNew : needRefundProjectBorrowPlanNew) {
                for (ProjectGuaranteeServicePlan plan : servicePlans) {
                    if (plan.getCurrentPeriod().equals(planNew.getPeriod())){
                        guaranteePlans.remove(planNew);
                    }
                }
            }
            log.info("处理已垫付期数后标的{}{}", refundOrder.getProjectId(),JSON.toJSONString(guaranteePlans));
            if(refundOrder.getManageFee().compareTo(BigDecimal.ZERO) > 0){
                List<RefundFeeDTO> feeList = feeCalcForRefundService.getRefundFeeDTOList(guaranteePlans, FeeTypeEnum.MANAGEMENT_FEE, refundOrder.getManageFee());
                List<RefundOrderDetailDTO> refundOrderDetailDTOS = this.dealServiceFee(refundOrder, feeList, project.getConsultingBusinessLicense(), FeeTypeEnum.MANAGEMENT_FEE);
                refundOrderDetailDTOs.addAll(refundOrderDetailDTOS);
            }
            if(refundOrder.getConsultingFee().compareTo(BigDecimal.ZERO) > 0){
                List<RefundFeeDTO> feeList = feeCalcForRefundService.getRefundFeeDTOList(guaranteePlans, FeeTypeEnum.CONSULTING_FEE, refundOrder.getConsultingFee());
                List<RefundOrderDetailDTO> refundOrderDetailDTOS = this.dealServiceFee(refundOrder, feeList, project.getConsultingBusinessLicense(), FeeTypeEnum.CONSULTING_FEE);
                refundOrderDetailDTOs.addAll(refundOrderDetailDTOS);
            }
        }

        return refundOrderDetailDTOs;
    }
    /**
     * @param refundOrder
     * @param feeList
     * @param feeTypeEnum
     * @return
     */
    private List<RefundOrderDetailDTO> dealServiceFee(RefundOrder refundOrder, List<RefundFeeDTO> feeList,String consultingBusinessLicense, FeeTypeEnum feeTypeEnum){
        Long projectId = refundOrder.getProjectId();
        String batchNo = refundOrder.getBatchNo();
        List<RefundOrderDetailDTO> resultList = new ArrayList<>();
        RefundRelation refundRelation;
        AccountConfig accountConfig;
        if(FeeTypeEnum.CONSULTING_FEE.equals(feeTypeEnum)){
            refundRelation = this.getFenRunRefundRelation(projectId, refundOrder.getTradeType());
            if(StringUtils.isEmpty(consultingBusinessLicense)){
                throw new BizException("营业执照编号为空");
            }
            AccountCompanyDTO accountCompanyDTO = refundCommonService.getConsultingByProjectId(projectId);
            accountConfig = new AccountConfig();
            accountConfig.setUserId(accountCompanyDTO.getUserId());
            accountConfig.setAccountId(accountCompanyDTO.getAccountId());
            accountConfig.setPlatformUserNo(accountCompanyDTO.getAccountNo());
        }else if(FeeTypeEnum.MANAGEMENT_FEE.equals(feeTypeEnum)){
            refundRelation = this.getFenYongRefundRelation(projectId, refundOrder.getTradeType());
            accountConfig = accountConfigMapper.selectByPrimaryKey(AccountConfigConstants.getPlatform());
        }else{
            throw new BizException("资金费用类型无法找到和存管的对应关系");
        }
        if(null == accountConfig){
            throw  new BizException("平台管理费或担保服务费无法找到接收用户");
        }
        for (RefundFeeDTO refundFeeDTO : feeList) {
            if(BigDecimal.ZERO.compareTo(refundFeeDTO.getRefundingMoney()) == 0){
                continue;
            }
            RefundOrderDetailDTO refundOrderDetailDTO = new RefundOrderDetailDTO();
            refundOrderDetailDTO.setId(snowflakeIdWorker.nextId());
            refundOrderDetailDTO.setRefundOrderId(refundOrder.getId());
            refundOrderDetailDTO.setBatchNo(batchNo);
            refundOrderDetailDTO.setProjectId(projectId);
            refundOrderDetailDTO.setBorrowUserId(refundOrder.getBorrowUserId());
            refundOrderDetailDTO.setDetailRequestNo(lanMaoSequence.getRequestNo());
            if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(refundOrder.getTradeType())){
                refundOrderDetailDTO.setTradeType(TransactionTypeEnum.REPAYMENT.name());
            } else{
                refundOrderDetailDTO.setTradeType(TransactionTypeEnum.COMPENSATORY.name());
            }
            refundOrderDetailDTO.setCreateTime(new Date());
            refundOrderDetailDTO.setUpdateTime(new Date());
            refundOrderDetailMapperExt.insertSelective(refundOrderDetailDTO);

            RefundOrderDetailBiz relation = new RefundOrderDetailBiz();
            relation.setId(snowflakeIdWorker.nextId());
            relation.setRefundOrderId(refundOrder.getId());
            relation.setBatchNo(batchNo);
            relation.setProjectId(projectId);
            relation.setBorrowUserId(refundOrder.getBorrowUserId());
            relation.setCurrentPeriod(-1);
            relation.setDetailRequestNo(refundOrderDetailDTO.getDetailRequestNo());
            relation.setBizType(refundRelation.getBusinessTypeEnum().name());
            relation.setBackPlanId(-1L);
            relation.setFreezeRequestNo(refundOrder.getFreezeRequestNo());
            relation.setSourceUserId(refundOrder.getSourceUserId());
            relation.setSourceAccountId(refundOrder.getSourceAccountId());
            relation.setSourcePlatformUserNo(refundOrder.getSourcePlatformUserNo());
            relation.setTargetUserId(refundRelation.getUserId());
            relation.setTargetPlatformUserNo(refundRelation.getPlatformUserNo());
            relation.setTargetAccountId(refundRelation.getAccountId());
            relation.setAmount(BigDecimal.ZERO);
            relation.setCreateTime(new Date());
            relation.setUpdateTime(new Date());
            relation.setTradeType(refundOrder.getTradeType());
            refundOrderDetailBizMapperExt.insertSelective(relation);

            // 担保公司或平台
            RefundOrderDetailBiz biz = new RefundOrderDetailBiz();
            biz.setId(snowflakeIdWorker.nextId());
            biz.setRefundOrderId(refundOrder.getId());
            biz.setBatchNo(batchNo);
            biz.setProjectId(projectId);
            biz.setBorrowUserId(refundOrder.getBorrowUserId());
            biz.setCurrentPeriod(refundFeeDTO.getPeriod());
            biz.setDetailRequestNo(refundOrderDetailDTO.getDetailRequestNo());
            if(FeeTypeEnum.CONSULTING_FEE.equals(feeTypeEnum)){
                biz.setBizType(BusinessTypeEnum.PROFIT.name());
                biz.setConsultingFee(refundFeeDTO.getRefundingMoney());
            } else if(FeeTypeEnum.MANAGEMENT_FEE.equals(feeTypeEnum)){
                biz.setBizType(BusinessTypeEnum.COMMISSION.name());
                biz.setManageFee(refundFeeDTO.getRefundingMoney());
            } else{
                throw new BizException("资金费用类型无法找到和存管的对应关系");
            }
            biz.setBackPlanId(-1L);
            biz.setFreezeRequestNo(refundOrder.getFreezeRequestNo());
            biz.setSourceUserId(refundOrder.getSourceUserId());
            biz.setSourceAccountId(refundOrder.getSourceAccountId());
            biz.setSourcePlatformUserNo(refundOrder.getSourcePlatformUserNo());
            biz.setTargetUserId(accountConfig.getUserId());
            biz.setTargetPlatformUserNo(accountConfig.getPlatformUserNo());
            biz.setTargetAccountId(accountConfig.getAccountId());
            biz.setAmount(refundFeeDTO.getRefundingMoney());
            biz.setCreateTime(new Date());
            biz.setUpdateTime(new Date());
            biz.setTradeType(refundOrder.getTradeType());
            refundOrderDetailBizMapperExt.insertSelective(biz);

            final List<RefundOrderDetailBiz> refundOrderDetailBizs = new ArrayList<>();
            // 分佣分润时此顺序十分关键
            refundOrderDetailBizs.add(relation);
            refundOrderDetailBizs.add(biz);
            refundOrderDetailDTO.setRefundOrderDetailBizList(refundOrderDetailBizs);
            resultList.add(refundOrderDetailDTO);
        }
        return resultList;
    }
    /**
     * 找到关联分润时需关联的存管用户号（为收取担保服务费）
     * @param projectId
     * @param tradeType
     * @return
     */
    private RefundRelation getFenRunRefundRelation(Long projectId, Byte tradeType){
        ProjectInvestorPlan relationFirst = projectInvestorPlanMapperExt.getRelationFirst(projectId);
        if(null != relationFirst){
            if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(tradeType)){
                return new RefundRelation(relationFirst.getPlatformUserNo(), relationFirst.getUserId(), relationFirst.getAccountId(), BusinessTypeEnum.REPAYMENT);
            } else{
                return new RefundRelation(relationFirst.getPlatformUserNo(), relationFirst.getUserId(), relationFirst.getAccountId(), BusinessTypeEnum.COMPENSATORY);
            }
        }else{
            ProjectInvestorPlan relationSecond = projectInvestorPlanMapperExt.getRelationSecond(projectId);
            if(null != relationSecond){
                if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(tradeType)){
                    return new RefundRelation(relationSecond.getPlatformUserNo(), relationSecond.getUserId(), relationSecond.getAccountId(), BusinessTypeEnum.REPAYMENT);
                } else{
                    return new RefundRelation(relationSecond.getPlatformUserNo(), relationSecond.getUserId(), relationSecond.getAccountId(), BusinessTypeEnum.COMPENSATORY);
                }
            }else{
                throw new BizException("分润时无法到关联的用户");
            }
        }
    }
    /**
     * 找到分佣时需关联的存管用户号（为收取平台管理费）
     * @param projectId
     * @return
     */
    private RefundRelation getFenYongRefundRelation(Long projectId, Byte tradeType){
        ProjectInvestorPlan relationFirst = projectInvestorPlanMapperExt.getRelationFirst(projectId);
        if(null != relationFirst){
            if(RefundTradeTypeEnum.REPAYMENT.getTradeType().equals(tradeType)){
                return new RefundRelation(relationFirst.getPlatformUserNo(), relationFirst.getUserId(), relationFirst.getAccountId(), BusinessTypeEnum.REPAYMENT);
            } else{
                return new RefundRelation(relationFirst.getPlatformUserNo(), relationFirst.getUserId(), relationFirst.getAccountId(), BusinessTypeEnum.COMPENSATORY);
            }
        }else{
            ProjectGuaranteePlan projectGuaranteePlan = projectGuaranteePlanMapperExt.getRelation(projectId);
            if(null != projectGuaranteePlan){
                return new RefundRelation(projectGuaranteePlan.getPlatformUserNo(), projectGuaranteePlan.getUserId(), projectGuaranteePlan.getAccountId(), BusinessTypeEnum.COMPENSATORY_REPAYMENT);
            }else{
                throw new BizException("分润时无法到关联的用户");
            }
        }
    }
    private List<Integer> spiltPeriods(String periods){
        List<Integer> periodList = new ArrayList<Integer>();
        if(StringUtils.isNotEmpty(periods)){
            String[] periodArray = periods.split(",");
            for(String period : periodArray){
                periodList.add(Integer.parseInt(period));
            }
        }
        return periodList.size()==0?null:periodList;
    }

    /**
     * 还款关系
     */
    @Data
    @AllArgsConstructor
    private static class RefundRelation{
        private String platformUserNo;
        private String userId;
        private Long accountId;
        private BusinessTypeEnum businessTypeEnum;
    }
}
